/*
 *      prom_enet_debug.c
 *
 *      philippe gaussier 2009/2010
 *
 */

/* #define DEBUG 1 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <enet/enet.h>

#include <sys/timeb.h>
#include <signal.h>
#include <math.h>
#include <bits/local_lim.h>

#include "basic_tools.h"
#include "public.h"
#include "net_message_debug_dist.h"
#include "prom_enet_debug.h"
#include "oscillo_kernel.h"
#include "reseau.h"

#include "japet_connect.h"



int japet_activated = 0;

sem_t japet_lock;
ENetHost *japet_host;
ENetAddress japet_address;
ENetPeer *japet_peer;

/*type_trame_init trame_def_groupe;*/


inline float convert_time(struct timeval my_time)
{
	float f_time;
	f_time = (float) (my_time.tv_sec - secsFirstCall) + (float) my_time.tv_usec / (1000.0 * 1000.0);
	return (f_time);
}

int no_message = 0;

/*************************************************************/
/* Attention: peut etre appeler depuis une section critique pour init */

/* ou pour l'envoi des tags de l'oscillo kernel                     */
/*void send_debug_data(type_connexion_udp *connexion, void *data, int packetSize, int channel_number)
{
	ENetEvent event;
	if (!connexion->peer)
	{
		PRINT_WARNING("pb 1...%s (peer==NULL)\n");
		return;
	}

	connexion->packet = enet_packet_create(data, packetSize, (ENET_PACKET_FLAG_RELIABLE & ENET_PACKET_FLAG_NO_ALLOCATE ));
	enet_peer_send(connexion->peer, channel_number, connexion->packet);  queue the packet to be sent to the peer over channel id 0 
}*/

void japet_enet_manager(void)
{
	char ip[HOST_NAME_MAX];
	int running = 1;
	ENetEvent event;
	ENetPacket *packet;
	size_t packetSize;
	type_com_groupe *def_com_group;
	
	while (running)
	{
		while (enet_host_service(japet_host, &event, 10) > 0)
		{
			switch (event.type)
			{
			case ENET_EVENT_TYPE_CONNECT:
				printf("Prométhé reçoit la demande de Japet\n");
				enet_address_get_host_ip(&event.peer->address, ip, HOST_NAME_MAX);
				kprints("A new client connected from ip %s:%i.\n", ip, event.peer->address.port);
				event.peer->data = NULL;
								
				
				/*connexion->packet = enet_packet_create(Nom du script, packetSize, ENET_PACKET_FLAG_RELIABLE);
				if (connexion->packet == NULL)  EXIT_ON_ERROR("The packet has not been created.");
				if (enet_peer_send (connexion->peer, ENET_DEF_SCRIPTNAME_CHANNEL, connexion->packet) !=0) EXIT_ON_ERROR("The packet has not been sent.");

				connexion->packet = enet_packet_create(Nombre de groupes dans le script, packetSize, ENET_PACKET_FLAG_RELIABLE);
				if (connexion->packet == NULL)  EXIT_ON_ERROR("The packet has not been created.");
				if (enet_peer_send (connexion->peer, ENET_DEF_GROUPSNUMBER_CHANNEL, connexion->packet) !=0) EXIT_ON_ERROR("The packet has not been sent.");*/
								
				packetSize = sizeof(type_com_groupe) * nbre_groupe;
				def_com_group = MANY_ALLOCATIONS(nbre_groupe, type_com_groupe);
				init_com_def_groupe(def_com_group);
				packet = enet_packet_create(def_com_group, packetSize, ENET_PACKET_FLAG_RELIABLE & ENET_PACKET_FLAG_NO_ALLOCATE);
				if (packet == NULL)  EXIT_ON_ERROR("The packet has not been created.");
				if (enet_peer_send (event.peer, ENET_DEF_GROUP_CHANNEL, packet) !=0) EXIT_ON_ERROR("The packet has not been sent.");
				free(def_com_group);
				/*
				connexion->packet = enet_packet_create(Tableau des neurones, packetSize, ENET_PACKET_FLAG_RELIABLE);
				if (connexion->packet == NULL)  EXIT_ON_ERROR("The packet has not been created.");
				if (enet_peer_send (connexion->peer, ENET_DEF_NEURONS_CHANNEL, connexion->packet) !=0) EXIT_ON_ERROR("The packet has not been sent.");

				connexion->packet = enet_packet_create(Tableau des laisons, packetSize, ENET_PACKET_FLAG_RELIABLE);
				if (connexion->packet == NULL)  EXIT_ON_ERROR("The packet has not been created.");				
				if (enet_peer_send (connexion->peer, ENET_DEF_LINKS_CHANNEL, connexion->packet) !=0) EXIT_ON_ERROR("The packet has not been sent.");*/
				
				sem_post(&(japet_lock));
				japet_activated = 1;
				break;
 
			case ENET_EVENT_TYPE_RECEIVE:
				if (event.channelID == ENET_COMMAND_CHANNEL)
				{
					switch (*(int*)event.peer->data)
					{
							case ENET_COMMAND_STOP_OSCILLO:
								oscillo_dist_activated = 0;
								break;
							case ENET_COMMAND_START_OSCILLO:
								oscillo_dist_activated = 1;
								break;
					}
				}
				break;

			case ENET_EVENT_TYPE_DISCONNECT:
				kprints("%s disconected.\n", (char*) event.peer->data);
				/* Reset the peer's client information. */
				event.peer->data = NULL;
				break;

			case ENET_EVENT_TYPE_NONE:
				kprints("ENET: none event \n");
				break;
			}
		}
	}
}




/* init network for udp connexion using enet : used for distant oscillo_kernel */
/* ip_adr= 127.0.0.1 par ex ou nom_adr=localhost... */

int japet_connect(char *ip_adr, int port)
{
	int error;
	size_t packetSize;
	ENetEvent event;
	pthread_t enet_thread;

	if (sem_init(&(japet_lock), 0, 0) != 0) EXIT_ON_SYSTEM_ERROR("Fail to init semaphore.");  /* attend que le message precedent ait ete envoye */

	/* network initialization: */
	if (enet_initialize() != 0) EXIT_ON_ERROR("An error occurred while initializing ENet.\nAn error occurred while initializing ENet.\n");

	atexit(enet_deinitialize); /* PG: A verifier si pas de conflit au niveau global de promethe */
	enet_time_set(0);

	japet_host = enet_host_create(NULL, 1, JAPET_NUMBER_OF_CHANNELS, ENET_UNLIMITED_BANDWITH,  ENET_UNLIMITED_BANDWITH);

	if (!japet_host) EXIT_ON_ERROR("An error occurred while trying to create an ENet client host.\n");

	if (enet_address_set_host(&(japet_address), ip_adr) != 0) EXIT_ON_ERROR("Error with address %s", ip_adr);
	japet_address.port = port;
	japet_peer = enet_host_connect(japet_host, &(japet_address), JAPET_NUMBER_OF_CHANNELS, 0);

	if (pthread_create(&enet_thread, NULL, (void*(*)(void*)) japet_enet_manager, NULL) != 0) EXIT_ON_ERROR("Unable to create thread.");
	return 0;
}

void quit_debug_client(type_connexion_udp *connexion)
{
	int event_return;


	if (connexion->data != NULL)
	{
		free(connexion->data);
		connexion->data = NULL;
	}
	if (connexion->peer)
	{
		enet_peer_disconnect(connexion->peer, 0);
		event_return = enet_host_service(connexion->host, &connexion->event, connexion->waitTime);
		if (event_return < 0) printf("error in event_host_service\n");

		printf("resetting peer...");
		fflush(stdout);
		enet_peer_reset(connexion->peer);
		printf(" done.\n");
	}

	printf("closing down...\n");
	fflush(stdout);
	enet_host_destroy(connexion->host);
	printf(" done.\n");
	enet_deinitialize();
	exit(1);
}




void quit_enet_token_oscillo_kernel()
{
/*	quit_debug_client(&network_debug_link);*/
}

/*void send_token_oscillo_kernel(int gpe, int phase, long temps)
{
	type_nn_message data_network;
	int res;

	data_network.type_trame = GROUP_DEBUG;
	no_message++;
	data_network.val_nn_message_id = NN_message_magic_card;
	data_network.no_message = no_message;
	data_network.time_stamp = temps;
	data_network.gpe = gpe;
	data_network.type_message = phase;
	res = sem_wait(&(network_debug_link.lock)); 
	send_debug_data(&network_debug_link, &data_network, sizeof(type_nn_message), ENET_GROUP_EVENT_CHANNEL);
	sem_post(&(network_debug_link.lock)); 
}*/
